// 形参默认值和参数数量问题
function _go() {
  function some(a, b, c = 3) {
    console.log(a, b, c);
  }

  some(1, 2);
  some(1, 2, 5);
  some(1)
}

// 展开运算符与push
function _push() {
  let arr = [1, 2, 3];
  let arr2 = [4, 5, 6];
  arr.push(...arr2);
  console.log(arr);
}

// 自动类型转换
function _to() {
  let a = '1';
  let b = '2';
  let c = '3';
  console.log(a + b + c);
  console.log([a, b, c].reduce((res, item) => res + 1 * item, 0));
}

// 简单的发布/订阅模式
function _pubsub() {
  function getObj() {
    let a = {};
    let cache = {};
    a.on = function (name, callback) {
      let some = cache[name];
      if (!some)
        cache[name] = [callback];
      else
        some.push(callback);
    };
    a.emit = function (name, ...args) {
      let some = cache[name];
      if (!some)
        return console.log('此事件没有绑定');
      some.forEach(fn => fn(...args));
    };
    a.un = function (name) {
      cache[name] = undefined;
    };
    return a;
  }

  let a = getObj();
  a.on('mul', (a, b) => console.log(a * b));
  a.emit('mul', 3, 5);
  a.emit('some', 'x', 'y');
  a.on('some', function (a, b) {
    console.log('1:', a, b);
  });
  a.emit('some', 'x', 'y');
  a.on('some', function (a, b) {
    console.log('2:', a, b);
  });
  a.emit('some', 'x', 'y');
  a.un('some');
  a.emit('some', 'x', 'y');
}

// 基于原型链的发布/订阅模式
function _protoPubsub() {
  function Some(name) {
    this.name = name;
  }
  (function () {
    let events = {};
    Some.prototype.$on = function (name, callback) {
      // 传参校验
      if (typeof callback !== 'function')
        return;
      let context = this;
      events[name] = events[name] || [];
      // 去重
      if (!events[name].some(ev => ev.context === context && ev.callback === callback))
        events[name].push({ context, callback });
    };
    Some.prototype.$emit = function (name, ...args) {
      if (!events[name])
        return;
      for (let i = 0; i < events[name].length; i++) {
        let ev = events[name][i];
        if (ev === null) {
          events[name].splice(i--, 1);
          continue;
        }
        ev.callback.call(ev.context, ...args);
      }
    };
    Some.prototype.$un = function (name, callback) {
      let context = this;
      events[name] = events[name] || [];
      events[name].forEach((ev, index) => {
        if (ev.callback === callback && ev.context === context)
          events[name][index] = null;
      })
    }
  })();
  function cb1() {
    console.log(1);
  }
  function cb2() {
    console.log(2);
    some.$un('some', cb2);
  }
  function cb3() {
    console.log(3);
  }
  function cb4() {
    console.log(4);
  }
  var some = new Some('a');
  some.$on('some', cb1);
  some.$on('some', cb2);
  some.$on('some', cb3);
  some.$on('some', cb4);
  some.$emit('some');
  console.log('---');
  some.$emit('some');
}

// 原型链继承
function _proto() {
  function Father() {

  }

  Father.prototype.go = function () {
    console.log('father');
  };

  function Son() {

  }

  Son.prototype = new Father();
  Son.prototype.constructor = Son;
  Son.prototype.go = function () {
    console.log('son');
  };
  let son = new Son();
  son.go();
  delete Son.prototype.go;
  son.go();
  console.log(son instanceof Son);
  console.log(son instanceof Father);
  console.log(son.constructor);
}

// generator
function _generator() {
  function* gen(x, y) {
    let z, result;
    yield (z = x + y);
    yield (result = z * x);
    return result
  }

  let g = gen(4, 5);
  console.log(g.next());
  console.log(g.next());
  console.log(g.next());
  console.log(g.next());
}

// 柯理化
function _curry() {
  function curry(fn, ...args) {
    return function () {
      let context = this;
      return fn.call(context, ...args, ...(arguments));
    }
  }

  function add(...args) {
    return args.reduce((count, item) => count + item)
  }

  let add100 = curry(add, 100);
  console.log(add100(1, 2, 3));
  let add110 = curry(add100, 10);
  console.log((add110(1, 2, 3)));
}

// 试验promise
function promise_await() {
  let get = delay => new Promise(resolve => setTimeout(() => resolve('ok ' + Date.now()), delay));
  let go = async () => {
    console.time('some');
    let tasks = [];
    for (let i = 0; i < 3; i++) {
      tasks.push(get(1000));
    }
    tasks.forEach(async task => console.log(await task));
    console.timeEnd('some');
  };
  go();
}

// 数字大写转小写
function _convertNumber() {
  function convertNumber(str) {
    if (!typeof str === 'string' || !str)
      return '';
    str = str
      .replace(/一/g, '1')
      .replace(/[二两]/g, '2')
      .replace(/三/g, '3')
      .replace(/四/g, '4')
      .replace(/五/g, '5')
      .replace(/六/g, '6')
      .replace(/七/g, '7')
      .replace(/八/g, '8')
      .replace(/九/g, '9')
      .replace(/(\d)十(\d)/g, ($, $1, $2) => '' + $1 + $2)
      .replace(/(\d)百(\d)/g, ($, $1, $2) => '' + $1 + $2)
      .replace(/(\d)千(\d)/g, ($, $1, $2) => '' + $1 + $2)
      .replace(/(\d)万(\d)/g, ($, $1, $2) => '' + $1 + $2)
      .replace(/(\d)十(?!\d)/g, ($, $1) => $1 + '0')
      .replace(/(\d)百(?!\d)/g, ($, $1) => $1 + '00')
      .replace(/(\d)千(?!\d)/g, ($, $1) => $1 + '000')
      .replace(/(\d)万(?!\d)/g, ($, $1) => $1 + '0000')
      .replace(/十(?=\d)/g, '1')
      .replace(/十/g, '10');
    let arr = str.split('零');
    return arr.length === 1 ? +str : arr.reduce((res, item) => +res + +item);
  }
  console.log(convertNumber('六万零三百零二'));
}

module.exports = _protoPubsub;
